package com.jyw.common.utils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;

/**
 * @author Created by ZhangCheng on 2023/06/02 (日期时间工具类)
 */
public class LocalTimeUtil {

    /**
     * 常用时间格式 yyyy-MM-dd HH:mm:ss
     */
    private static final DateTimeFormatter USUAL_DATETIME_FORMATTER = TimeFormat.LONG_DATE_PATTERN_LINE.dateTimeFormatter;

    private LocalTimeUtil() {
    }

    //--- LocalDate String covert 转换---

    /**
     * 字符串日期转为LocalDate 格式yyyy-MM-dd
     *
     * @param strDate
     * @return
     */
    public static LocalDate parseShortLocalDate(String strDate) {
        DateTimeFormatter dateTimeFormatter = TimeFormat.SHORT_DATE_PATTERN_LINE.dateTimeFormatter;
        return LocalDate.parse(strDate, dateTimeFormatter);
    }

    /**
     * 字符串日期转为LocalDate 格式yyyy年MM月dd日
     *
     * @param strDate
     * @return
     */
    public static LocalDate parseChinaLocalDate(String strDate) {
        DateTimeFormatter dateTimeFormatter = TimeFormat.SHORT_DATE_PATTERN_CHINA.dateTimeFormatter;
        return LocalDate.parse(strDate, dateTimeFormatter);
    }

    /**
     * 字符串日期转为LocalDate，格式yyyy/MM/dd
     *
     * @param strDate
     * @return
     */
    public static LocalDate parseSlashLocalDate(String strDate) {
        DateTimeFormatter dateTimeFormatter = TimeFormat.SHORT_DATE_PATTERN_SLASH.dateTimeFormatter;
        return LocalDate.parse(strDate, dateTimeFormatter);
    }

    /**
     * 字符串日期转为LocalDate 格式自定义
     *
     * @param strDate 字符串日期
     * @param pattern 格式化表达式
     * @return
     */
    public static LocalDate parseLocalDate(String strDate, String pattern) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        return LocalDate.parse(strDate, dateTimeFormatter);
    }

    /**
     * 获取日期字符串 格式yyyy-MM-dd
     *
     * @param localDate
     * @return
     */
    public static String formatShortLocalDate(LocalDate localDate) {
        DateTimeFormatter dateTimeFormatter = TimeFormat.SHORT_DATE_PATTERN_LINE.dateTimeFormatter;
        return formatLocalDateToStr(localDate, dateTimeFormatter);
    }

    /**
     * 获取日期字符串 格式yyyy年MM月dd日
     *
     * @param localDate
     * @return
     */
    public static String formatChinaLocalDate(LocalDate localDate) {
        DateTimeFormatter dateTimeFormatter = TimeFormat.SHORT_DATE_PATTERN_CHINA.dateTimeFormatter;
        return formatLocalDateToStr(localDate, dateTimeFormatter);
    }

    /**
     * 获取日期字符串，格式yyyy/MM/dd
     *
     * @param localDate
     * @return
     */
    public static String formatSlashLocalDate(LocalDate localDate) {
        DateTimeFormatter dateTimeFormatter = TimeFormat.SHORT_DATE_PATTERN_SLASH.dateTimeFormatter;
        return formatLocalDateToStr(localDate, dateTimeFormatter);
    }

    /**
     * 传入日期时间，格式化LocalDate时间
     *
     * @param localDate
     * @param dateTimeFormatter
     * @return
     */
    public static String formatLocalDateToStr(LocalDate localDate, DateTimeFormatter dateTimeFormatter) {
        return dateTimeFormatter.format(localDate);
    }

    //--- LocalDateTime String covert 转换---

    /**
     * 字符串日期转为LocalDateTime yyyy-MM-dd HH:mm:ss
     *
     * @param strDate 字符串日期
     * @return
     */
    public static LocalDateTime parseUsualLocalDateTime(String strDate) {
        DateTimeFormatter dateTimeFormatter = TimeFormat.LONG_DATE_PATTERN_LINE.dateTimeFormatter;
        return LocalDateTime.parse(strDate, dateTimeFormatter);
    }

    /**
     * 字符串日期转为LocalDateTime
     *
     * @param strDate 字符串日期
     * @param pattern 格式化表达式
     * @return
     */
    public static LocalDateTime parseLocalDateTime(String strDate, String pattern) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        return LocalDateTime.parse(strDate, dateTimeFormatter);
    }


    /**
     * 传入LocalDateTime，格式化为字符串 yyyy-MM-dd HH:mm:ss
     *
     * @param localDateTime
     * @return
     */
    public static String formatUsualLocalDateTime(LocalDateTime localDateTime) {
        return formatLocalDateTime(localDateTime, USUAL_DATETIME_FORMATTER);
    }

    /**
     * 传入日期时间，格式化LocalDateTime时间为字符串
     *
     * @param localDateTime
     * @param dateTimeFormatter
     * @return
     */
    public static String formatLocalDateTime(LocalDateTime localDateTime, DateTimeFormatter dateTimeFormatter) {
        return dateTimeFormatter.format(localDateTime);
    }

    //--- LocalTime String covert 转换---

    /**
     * 字符串日期转为LocalTime HH:mm:ss
     *
     * @param strDate 字符串日期
     * @return
     */
    public static LocalTime parseLocalTime(String strDate) {
        DateTimeFormatter dateTimeFormatter = TimeFormat.LOCAL_TIME_PATTERN_LINE.dateTimeFormatter;
        return LocalTime.parse(strDate, dateTimeFormatter);
    }

    /**
     * 字符串日期转为LocalTime 格式自定义
     *
     * @param strDate 字符串日期
     * @param pattern 格式化表达式
     * @return
     */
    public static LocalTime parseLocalTime(String strDate, String pattern) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        return LocalTime.parse(strDate, dateTimeFormatter);
    }

    /**
     * 传入LocalTime，格式化为时间字符串
     *
     * @param localTime
     * @param pattern
     * @return
     */
    public static String formatLocalTime(LocalTime localTime,String pattern) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        return dateTimeFormatter.format(localTime);
    }

    /**
     * 传入LocalTime，格式化为时间字符串 HH:mm:ss
     *
     * @param localTime
     * @return
     */
    public static String formatLocalTimeToStr(LocalTime localTime) {
        DateTimeFormatter dateTimeFormatter = TimeFormat.LOCAL_TIME_PATTERN_LINE.dateTimeFormatter;
        return dateTimeFormatter.format(localTime);
    }

    // ---localDate localDateTime date---

    /**
     * localDateTime转date
     *
     * @param localDateTime
     * @return
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        return Date.from(zdt.toInstant());
    }

    //--- add time 增加日期时间---

    /**
     * 将某个日期增加指定天数，并返回当天 00:00:00。如果传入负数，则为减。
     *
     * @param localDateTime
     * @param amount
     * @return
     */
    public static LocalDateTime firstTimeOfDay(final LocalDateTime localDateTime, final long amount) {
        LocalDateTime firstOfDay = localDateTime.plusDays(amount).with(LocalTime.MIN);
        return firstOfDay;
    }

    /**
     * 将某个日期增加指定天数，并返回当天 23:59:59。如果传入负数，则为减。
     *
     * @param localDateTime
     * @param amount
     * @return
     */
    public static LocalDateTime lastTimeOfDay(final LocalDateTime localDateTime, final long amount) {
        LocalDateTime endOfDay = localDateTime.plusDays(amount).with(LocalTime.MAX);
        return endOfDay;
    }

    /**
     * 将某个日期增加指定周数，并返回当周第一天 00:00:00。如果传入负数，则为减。
     *
     * @param localDateTime
     * @param amount
     * @return
     */
    public static LocalDateTime firstDayOfWeek(final LocalDateTime localDateTime, final long amount) {
        LocalDateTime firstOfDay = localDateTime.plusWeeks(amount).with(DayOfWeek.MONDAY).with(LocalTime.MIN);
        return firstOfDay;
    }

    /**
     * 将某个日期增加指定周数，并返回当周最后一天 23:59:59。如果传入负数，则为减。
     *
     * @param localDateTime
     * @param amount
     * @return
     */
    public static LocalDateTime lastDayOfWeek(final LocalDateTime localDateTime, final long amount) {
        LocalDateTime endOfDay = localDateTime.plusWeeks(amount).with(DayOfWeek.SUNDAY).with(LocalTime.MAX);
        return endOfDay;
    }

    /**
     * 将某个日期增加指定月数，并返回当月第一天 00:00:00。如果传入负数，则为减。
     *
     * @param localDateTime
     * @param amount
     * @return
     */
    public static LocalDateTime firstDayOfMonth(final LocalDateTime localDateTime, final long amount) {
        LocalDateTime firstOfDay = localDateTime.plusMonths(amount).with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
        return firstOfDay;
    }

    /**
     * 将某个日期增加指定月数，并返回当月最后一天 23:59:59。如果传入负数，则为减。
     *
     * @param localDateTime
     * @param amount
     * @return
     */
    public static LocalDateTime lastDayOfMonth(final LocalDateTime localDateTime, final int amount) {
        LocalDateTime endOfDay = localDateTime.plusMonths(amount).with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
        return endOfDay;
    }

    /**
     * 将某个日期增加指定年数，并返回当年第一天 00:00:00。如果传入负数，则为减。
     *
     * @param localDateTime
     * @param amount
     * @return
     */
    public static LocalDateTime firstDayOfYear(final LocalDateTime localDateTime, final long amount) {
        LocalDateTime firstOfDay = localDateTime.plusMonths(amount).with(TemporalAdjusters.firstDayOfYear()).with(LocalTime.MIN);
        return firstOfDay;
    }

    /**
     * 将某个日期增加指定年数，并返回当年最后一天 23:59:59。如果传入负数，则为减。
     *
     * @param localDateTime
     * @param amount
     * @return
     */
    public static LocalDateTime lastDayOfYear(final LocalDateTime localDateTime, final int amount) {
        LocalDateTime endOfDay = localDateTime.plusMonths(amount).with(TemporalAdjusters.lastDayOfYear()).with(LocalTime.MAX);
        return endOfDay;
    }

    /**
     * 将某个日期增加指定分钟，并返回结果。如果传入负数，则为减。
     *
     * @param localDateTime
     * @param amount
     * @return
     */
    public static LocalDateTime addLocalMonths(final LocalDateTime localDateTime, final long amount) {
        LocalDateTime newLocalDateTime = localDateTime.plusMonths(amount);
        return newLocalDateTime;
    }

    /**
     * 将某个日期增加指定分钟，并返回结果。如果传入负数，则为减。
     *
     * @param localDateTime
     * @param amount
     * @return
     */
    public static LocalDateTime addLocalMinutes(final LocalDateTime localDateTime, final long amount) {
        LocalDateTime newLocalDateTime = localDateTime.plusMinutes(amount);
        return newLocalDateTime;
    }

    /**
     * 将某个日期增加指定秒，并返回结果。如果传入负数，则为减。
     *
     * @param localDateTime
     * @param amount
     * @return
     */
    public static LocalDateTime addLocalSeconds(final LocalDateTime localDateTime, final long amount) {
        LocalDateTime newLocalDateTime = localDateTime.plusSeconds(amount);
        return newLocalDateTime;
    }

    //---count time 计算日期时间差---

    /**
     * 计算日期天数差
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static long periodDays(LocalDate startDate, LocalDate endDate) {
        long days = Period.between(startDate, endDate).getDays();
        return days;
    }

    /**
     * 计算时间天数差
     *
     * @param startTime
     * @param endTime
     * @return
     */
    public static long durationDays(LocalDateTime startTime, LocalDateTime endTime) {
        Duration duration = Duration.between(startTime, endTime);
        return duration.toDays();
    }

    /**
     * 计算时间小时差
     *
     * @param startTime
     * @param endTime
     * @return
     */
    public static long durationHours(LocalDateTime startTime, LocalDateTime endTime) {
        Duration duration = Duration.between(startTime, endTime);
        return duration.toHours();
    }

    /**
     * 时间格式枚举
     */
    public enum TimeFormat {

        /**
         * 日期格式：yyyyMMdd
         */
        NUM_DATE_PATTERN_LINE("yyyyMMdd"),

        /**
         * 日期格式：yyyy-MM-dd
         */
        SHORT_DATE_PATTERN_LINE("yyyy-MM-dd"),

        /**
         * 日期格式：yyyy/MM/dd
         */
        SHORT_DATE_PATTERN_SLASH("yyyy/MM/dd"),

        /**
         * 日期格式：yyyy年MM月dd日
         */
        SHORT_DATE_PATTERN_CHINA("yyyy年MM月dd日"),

        /**
         * 时间格式：yyyy-MM-dd HH:mm:ss
         */
        LONG_DATE_PATTERN_LINE("yyyy-MM-dd HH:mm:ss"),

        /**
         * 时间格式：yyyy-MM-dd HH:mm
         */
        SPECIAL_DATE_PATTERN_LINE("yyyy-MM-dd HH:mm"),

        /**
         * 时间格式：HH:mm:ss
         */
        LOCAL_TIME_PATTERN_LINE("HH:mm:ss");

        /**
         * 使用transient关键字不序列化某个变量
         */
        private transient DateTimeFormatter dateTimeFormatter;

        TimeFormat(String pattern) {
            dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        }
    }
}
